﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Linq.Expressions;

using System.Data.Entity;
using System.ComponentModel;
using ZY.EntityFrameWork.Core.Repositories.Interface;
using ZY.EntityFrameWork.Core.Model.Entity;
using ZY.EntityFrameWork.Core.Context;
using ZY.EntityFrameWork.Core.DBHelper;

namespace ZY.EntityFrameWork.Core.Repositories.Impl
{
    /// <summary>
    /// 数据访问层基类实现层
    /// </summary>
    /// <typeparam name="TEntity">实体对象类型</typeparam>
    public abstract class BaseRepository<TEntity> : IBaseRepository<TEntity> where TEntity : BaseEntity
    {
        #region 变量及构造函数

        /// <summary>
        /// 基于EF框架的DbContext对象
        /// </summary>
        protected IEFUnitOfWorkContext EFContext;

        /// <summary>
        /// 是否为降序
        /// </summary>
        public bool IsDescending { get; set; }

        /// <summary>
        /// 排序属性
        /// </summary>
        public string SortPropertyName { get; set; }

        /// <summary>
        /// 参数化构造函数
        /// </summary>
        /// <param name="context">DbContext对象</param>
        public BaseRepository(IUnitOfWorkContext unitContext)
        {
            if (unitContext is IEFUnitOfWorkContext)
            {
                this.EFContext = unitContext as IEFUnitOfWorkContext;
            }               

            this.IsDescending     = true;
            this.SortPropertyName = "ID";
        }

        #endregion

        #region 增删改

        /// <summary>
        /// 插入实体记录
        /// </summary>
        /// <param name="entity"> 实体对象 </param>
        /// <param name="isSave"> 是否执行保存 </param>
        /// <returns> 操作影响的行数 </returns>
        public virtual int Insert(TEntity entity, bool isSave = true)
        {
            // 参数有效性检查
            ArgumentValidation.CheckForNullReference(entity, "传入的对象t为空");
            // 对象加入仓储上下文（暂不提交数据库）
            EFContext.RegisterNew(entity);
            // 立即提交或暂缓执行
            return isSave ? EFContext.Commit() : 0;
        }

        /// <summary>
        /// 批量插入实体记录集合
        /// </summary>
        /// <param name="entities"> 实体记录集合 </param>
        /// <param name="isSave"> 是否执行保存 </param>
        /// <returns> 操作影响的行数 </returns>
        public virtual int Insert(IEnumerable<TEntity> entities, bool isSave = true)
        {
            // 参数有效性检查
            ArgumentValidation.CheckForNullReference(entities, "传入的对象t为空");
            // 对象加入仓储上下文（暂不提交数据库）
            EFContext.RegisterNew(entities);
            // 立即提交或暂缓执行
            return isSave ? EFContext.Commit() : 0;
        }

        /// <summary>
        /// 删除指定编号的记录
        /// </summary>
        /// <param name="id"> 实体记录编号 </param>
        /// <param name="isSave"> 是否执行保存 </param>
        /// <returns> 操作影响的行数 </returns>
        public virtual int Delete(object id, bool isSave = true)
        {
            // 参数有效性检查
            ArgumentValidation.CheckForNullReference(id, "传入的对象id为空");
            // 实体记录在数据库是否存在
            TEntity entity = EFContext.Set<TEntity>().Find(id);
            // 记录存在则立即执行，否则返回0
            return entity != null ? Delete(entity, isSave) : 0;
        }

        /// <summary>
        /// 删除实体记录
        /// </summary>
        /// <param name="entity"> 实体对象 </param>
        /// <param name="isSave"> 是否执行保存 </param>
        /// <returns> 操作影响的行数 </returns>
        public virtual int Delete(TEntity entity, bool isSave = true)
        {
            // 参数有效性检查
            ArgumentValidation.CheckForNullReference(entity, "传入的对象t为空");
            // 对象加入仓储上下文（暂不提交数据库）
            EFContext.RegisterDeleted(entity);
            // 立即提交或暂缓执行
            return isSave ? EFContext.Commit() : 0;
        }

        /// <summary>
        /// 删除实体记录集合
        /// </summary>
        /// <param name="entities"> 实体记录集合 </param>
        /// <param name="isSave"> 是否执行保存 </param>
        /// <returns> 操作影响的行数 </returns>
        public virtual int Delete(IEnumerable<TEntity> entities, bool isSave = true)
        {
            // 参数有效性检查
            ArgumentValidation.CheckForNullReference(entities, "传入的对象entities为空");
            // 对象加入仓储上下文（暂不提交数据库）
            EFContext.RegisterDeleted(entities);
            // 立即提交或暂缓执行
            return isSave ? EFContext.Commit() : 0;
        }

        /// <summary>
        /// 删除所有符合特定表达式的数据
        /// </summary>
        /// <param name="predicate"> 查询条件谓语表达式 </param>
        /// <param name="isSave"> 是否执行保存 </param>
        /// <returns> 操作影响的行数 </returns>
        public virtual int Delete(Expression<Func<TEntity, bool>> predicate, bool isSave = true)
        {
            // 参数有效性检查
            ArgumentValidation.CheckForNullReference(predicate, "传入的对象predicate为空");
            // 依据条件表达式查询实体记录
            List<TEntity> entities = EFContext.Set<TEntity>().Where(predicate).ToList();
            // 记录存在则立即执行，否则返回0
            return entities.Count > 0 ? Delete(entities, isSave) : 0;
        }

        /// <summary>
        /// 更新实体记录
        /// </summary>
        /// <param name="entity"> 实体对象 </param>
        /// <param name="isSave"> 是否执行保存 </param>
        /// <returns> 操作影响的行数 </returns>
        public virtual int Update(TEntity entity, bool isSave = true)
        {
            // 参数有效性检查
            ArgumentValidation.CheckForNullReference(entity, "传入的对象entity为空");
            // 对象加入仓储上下文（暂不提交数据库）
            EFContext.RegisterModified(entity);
            // 立即提交或暂缓执行
            return isSave ? EFContext.Commit() : 0;
        }

        /// <summary>
        /// 批量更新实体记录
        /// </summary>
        /// <param name="entities"></param>
        /// <param name="isSave"></param>
        /// <returns></returns>
        public virtual int Update(IEnumerable<TEntity> entities, bool isSave = true)
        {
            // 参数有效性检查
            ArgumentValidation.CheckForNullReference(entities, "传入的对象entity为空");
            // 对象加入仓储上下文（暂不提交数据库）
            EFContext.RegisterModified(entities);
            // 立即提交或暂缓执行
            return isSave ? EFContext.Commit() : 0;
        }

        #endregion

        #region 查询 返回IQueryable<TEntity>使用延迟加载技术

        /// <summary>
        /// 检查实体是否存在
        /// </summary>
        /// <param name="predicate">查询条件表达式</param>
        /// <returns>是否存在</returns>
        public virtual bool CheckExists(Expression<Func<TEntity, bool>> predicate)
        {
            // 参数有效性检查
            ArgumentValidation.CheckForNullReference(predicate, "传入的对象key为空");
            // 存在返回true，否则false
            return EFContext.Set<TEntity>().Count(predicate) == 0 ? false :true ;
        }

        /// <summary>
        /// 查找指定主键的实体记录
        /// </summary>
        /// <param name="key"> 指定主键 </param>
        /// <returns> 符合编号的记录，不存在返回null </returns>
        public virtual TEntity GetByKey(object key)
        {
            // 参数有效性检查
            ArgumentValidation.CheckForNullReference(key, "传入的对象key为空");
            // 执行查询
            return EFContext.Set<TEntity>().Find(key);
        }

        /// <summary>
        /// 根据条件查询数据库,如果存在返回第一个对象
        /// </summary>
        /// <param name="match">条件表达式</param>
        /// <returns>存在则返回指定的第一个对象,否则返回默认值</returns>
        public virtual TEntity FindSingle(Expression<Func<TEntity, bool>> match)
        {
            // 执行查询
            return EFContext.Set<TEntity>().FirstOrDefault(match);
        }
     
        /// <summary>
        /// 返回可查询的记录源
        /// </summary>
        /// <returns></returns>
        public virtual IQueryable<TEntity> GetQueryable()
        {
            // 执行查询
            return EFContext.Set<TEntity>();
        }

        /// <summary>
        /// 根据条件查询数据库,并返回对象集合
        /// </summary>
        /// <param name="match">条件表达式</param>
        /// <returns></returns>
        public virtual IQueryable<TEntity> Find(Expression<Func<TEntity, bool>> match)
        {
            // 执行查询
            return EFContext.Set<TEntity>().Where(match);
        }

        #endregion
    }
}
